import { z } from "zod"
import { newTool } from ".."
import sdk from "../../../sdk"
import { RowSearchParams, SortOrder } from "@budibase/types"

export default [
  newTool({
    name: "list_rows",
    description: "List rows in a given table",
    parameters: z.object({
      tableId: z.string().describe("The ID of the table to list rows from"),
      limit: z.number().nullish().describe("Maximum number of rows to return"),
      startKey: z.string().nullish().describe("Start key for pagination"),
    }),
    handler: async ({ tableId }) => {
      const rows = await sdk.rows.fetch(tableId)
      return { rows }
    },
  }),

  newTool({
    name: "get_row",
    description: "Get a specific row by ID",
    parameters: z.object({
      tableId: z.string().describe("The ID of the table"),
      rowId: z.string().describe("The ID of the row to retrieve"),
    }),
    handler: async ({ tableId, rowId }) => {
      const row = await sdk.rows.find(tableId, rowId)
      return { row }
    },
  }),

  newTool({
    name: "create_row",
    description:
      "Create a new row. Only include fields that match the table schema. " +
      "CRITICAL: Use plain text values only. Do NOT include HTML tags, markdown formatting, " +
      "or content containing quotes, backslashes, or special characters - these break JSON parsing. " +
      "Summarize or strip complex content. Max 500 characters per field.",
    parameters: z.object({
      tableId: z.string().describe("The ID of the table to create the row in"),
      data: z
        .record(z.string(), z.any())
        .describe(
          'Row data as a JSON object. Example: {"name": "John", "age": 30}. ' +
            "Do NOT nest this inside a string; pass the object directly. " +
            "Values must be plain text - no HTML, markdown, or special characters."
        ),
    }),
    handler: async ({ tableId, data }) => {
      const row = await sdk.rows.save(tableId, data as any, undefined)
      return { row }
    },
  }),

  newTool({
    name: "update_row",
    description:
      "Update an existing row. " +
      "CRITICAL: Use plain text values only. Do NOT include HTML tags, markdown formatting, " +
      "or content containing quotes, backslashes, or special characters - these break JSON parsing. " +
      "Summarize or strip complex content. Max 500 characters per field.",
    parameters: z.object({
      tableId: z.string().describe("The ID of the table"),
      rowId: z.string().describe("The ID of the row to update"),
      data: z
        .record(z.string(), z.any())
        .describe(
          'The updated data as a JSON object. Example: {"name": "Jane"}. ' +
            "Do NOT nest this inside a string; pass the object directly. " +
            "Values must be plain text - no HTML, markdown, or special characters."
        ),
    }),
    handler: async ({ tableId, rowId, data }) => {
      const rowData = { ...data, _id: rowId }
      const row = await sdk.rows.save(tableId, rowData, undefined)
      return { row }
    },
  }),

  newTool({
    name: "search_rows",
    description:
      "Search for rows in a table based on criteria. " +
      "IMPORTANT: You can ONLY filter on fields that exist in the table schema. " +
      "Use get_table or list_tables first to see available field names. " +
      "Searching on non-existent fields will fail.",
    parameters: z.object({
      tableId: z.string().describe("The ID of the table to search"),
      query: z
        .record(z.string(), z.any())
        .nullish()
        .describe(
          `Query filters object. Structure: { operator: { fieldName: value } }. ` +
            `CRITICAL: fieldName must match an existing column in the table schema exactly (case-sensitive). ` +
            `Valid operators: "equal", "notEqual", "empty", "notEmpty", "fuzzy", "string", "contains", "notContains", "containsAny", "oneOf", "range". ` +
            `Examples: ` +
            `Find where status equals "active": {"equal": {"status": "active"}}. ` +
            `Find where name is not empty: {"notEmpty": {"name": true}}. ` +
            `Find where price is within the range of 10 to 100: {"range": {"price": {"low": 10, "high": 100}}}.`
        ),
      sort: z
        .object({
          column: z.string().describe("Column to sort by"),
          order: z.enum(["ascending", "descending"]).describe("Sort order"),
        })
        .nullish()
        .describe("Sort configuration"),
      limit: z.number().nullish().describe("Maximum number of results"),
    }),
    handler: async ({ tableId, query, sort, limit }) => {
      const searchParams: RowSearchParams = {
        tableId,
        query: query || {},
        limit: limit ?? undefined,
      }
      if (sort) {
        searchParams.sort = sort.column
        searchParams.sortOrder =
          sort.order === SortOrder.ASCENDING
            ? SortOrder.ASCENDING
            : SortOrder.DESCENDING
      }

      const result = await sdk.rows.search(searchParams)
      return { rows: result.rows }
    },
  }),
]
